package cn.bonoon.kernel.web.controllers;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.bonoon.handler.AutoManager;
import cn.bonoon.kernel.VisibleScope;
import cn.bonoon.kernel.events.BaseEvent;
import cn.bonoon.kernel.events.DialogEvent;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.menus.MenuableDefinition;
import cn.bonoon.kernel.web.StandardKeyChecker;
import cn.bonoon.kernel.web.handlers.AbstractDialogHandler;
import cn.bonoon.kernel.web.handlers.AbstractOperateHandler;
import cn.bonoon.kernel.web.handlers.IExecutable;
import cn.bonoon.kernel.web.handlers.loader.AbstractLoaderHandler;
import cn.bonoon.kernel.web.models.DialogModel;
import cn.bonoon.kernel.web.models.JsonResult;

/**
 * <pre>
 * 提供三个访问接口的支持：
 * 1. !{key}/index.do 该功能的入口 {@link AbstractPanelController#get(HttpServletRequest, String)}
 * 2. !{mid}/{key}!exe.do 用于动态加载界面{@link #exe(HttpServletRequest, Object, String, String)}，如：弹出对话框、加载div等。。。
 * 3. !{mid}/{key}!exe.ajax 用于ajax操作{@link #ajax(HttpServletRequest, Object, String, String)}，如：加载数据、提交数据、执行操作等。。。
 * </pre>
 * @author jackson
 *
 */
public abstract class AbstractLayoutController extends AbstractPanelController{

	@Autowired
	protected AutoManager autoManager;
	
	/**
	 * <pre>
	 * 访问时需要的参数，如：提交数据、加载页面的参数等。
	 * 
	 * 首次进入功能的时候目录是不需要参数的，所以这个函数默认返回null
	 * </pre>
	 */
	@ModelAttribute("ObjectParams")
	public final Object objectParams(@PathVariable("key") String key){
		IExecutable handler = autoManager.handler(key);
		if(null != handler) {
			return handler.buildParams();
		}
		return null;
	}
	
	/**
	 * <pre>
	 * 弹出对话框的入口
	 * 
	 * 默认的key包括：
	 * detail,insert,update和其它自定义的处理事件
	 * 
	 * 有过<code>$(div).load(url);</code>的方式来加载弹出对话框界面
	 * </pre>
	 */
	@RequestMapping(value = "!{mid}/{key}!exe.do", method = {POST, GET})
	public final Object exe(HttpServletRequest request, 
			@ModelAttribute("ObjectParams") Object params,
			@PathVariable("mid") String mid, 
			@PathVariable("key") String key){
		try{
			return __execute(autoManager.handler(key), request, params, mid);
		}catch(Exception th){
			return errorPanel(th);
		}
	}
	
	/**
	 * <pre>
	 * 子类可以通过重写该方法来提供更多的处理器来处理不同的请求；
	 * 如：弹出对话框，加载另一个页面等
	 * 这个方法是非ajax方式的处理
	 * </pre>
	 */
	protected Object __execute(IExecutable handler, HttpServletRequest request, Object params, String mid) throws Exception{
		initRequest(request);
		if(handler instanceof AbstractDialogHandler){
			DialogEvent event = new DialogEvent(applicationContext, mid, request, params, getUser());
			
			//需要控制弹出对话框上的按钮的操作权限
			DialogModel model = new DialogModel(handler.getKey(), mid, request);
			MenuableDefinition item = moduleManager.item(mid);
			if(null == item){
				model.addObject(StandardKeyChecker.CHECKER_PROPERTY_NAME, StandardKeyChecker.EMPTY);
			}else{
				event.setScope(getScope(item));
				StandardKeyChecker.setChecker(model, item, event, userService.policy());
			}
			return ((AbstractDialogHandler) handler).execute(model, event);
		}
		return null;
	}
	
	/**  取得限制访问的范围，该限制范围的定义可以在菜单文件里，如果子类重写，则以子类的字义为主 */
	protected VisibleScope getScope(MenuableDefinition item){
		return item.getScope();
	}
	
	@ResponseBody
	@RequestMapping(value = "!{mid}/{key}!exe.ajax", method = {POST, GET})
	public final Object ajax(HttpServletRequest request, 
			@ModelAttribute("ObjectParams") Object params,
			@PathVariable("mid") String mid, 
			@PathVariable("key") String key){
		try{
			return __ajax(autoManager.handler(key), request, params, mid);
		}catch(Exception th){
			return JsonResult.error(th);
		}
	}
	
	protected Object __ajax(IExecutable handler, HttpServletRequest request, Object params, String mid) throws Exception{
		initRequest(request);
		if(handler instanceof AbstractOperateHandler){
			OperateEvent event = new OperateEvent(applicationContext, mid, request, params, getUser());
			__initEvent(mid, event);
			return ((AbstractOperateHandler) handler).execute(event);
		}else if(handler instanceof AbstractLoaderHandler){
			ReadEvent event = new ReadEvent(applicationContext, request, params, getUser());
			__initEvent(mid, event);
			AbstractLoaderHandler loadHandler = (AbstractLoaderHandler) handler;
			__initLoader(loadHandler, event);
			return loadHandler.execute(event);
		}
		return null;
	}
	
	protected void __initLoader(AbstractLoaderHandler loadHandler, ReadEvent event)throws Exception{ }
	
	/** 子类可以对处理事件的对象进行一些初始化工作 */
	protected void __initEvent(String mid, BaseEvent event){
		MenuableDefinition item = moduleManager.item(mid);
		if(null != item){
			event.setScope(getScope(item));
		}
	}
}
